package Gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import tools.FastLMTSkeletonCreator;
import tools.FastLMTSkeletonCreator.Logger;

import controller.Notification;
import controller.NotificationCenter;
import controller.NotificationObserver;

import Triangulation.EdgeGenerator;
import Triangulation.FastLMTTriangulator;

import static controller.Globals.*;


public class BottomPanel extends JPanel  implements NotificationObserver {
	
	private EdgeGenerator triangulator;
    private JSlider zoomSlider;
    private TriangleDisplay triangleDisplay;
    private String progressText;
    private int progress = 0;
    private int roundingFactor = 100;
    
    class SliderListener implements ChangeListener {
        public void stateChanged(ChangeEvent e) {
            JSlider source = (JSlider)e.getSource();
            double fps = (double)source.getValue();
            triangleDisplay.setZoom(fps / 100.0);
        }
    }
    
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	BottomPanel() {
		// register for notifications
        NotificationCenter nc = NotificationCenter.defaultNotificationCenter();
        nc.addObserver(Notification.willStartProcessing, this);
        nc.addObserver(Notification.didProcessXPercent, this);
        
		setPreferredSize(new Dimension(400, 60));
		setBorder(BorderFactory.createLineBorder (Color.white, 1));
	    setBackground(Color.white);
	    setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS)); 
	    
	    add(Box.createHorizontalGlue());
	    
	    JLabel caption = new JLabel();
	    caption.setText("Zoom:");
	    add(caption); 
	    
        zoomSlider = new JSlider(JSlider.HORIZONTAL, 0, 200, 100);
        zoomSlider.setMajorTickSpacing(100);
        zoomSlider.setMinorTickSpacing(0);
        zoomSlider.setPaintLabels(true);
        zoomSlider.setPaintTicks(true);
        zoomSlider.setMaximumSize(new Dimension(60, 50));
        zoomSlider.addChangeListener(new SliderListener());
        zoomSlider.setBackground(Color.white);
        add(zoomSlider); 
        add(Box.createRigidArea(new Dimension(20, 10))); 
	}
	
	private double round(double value) {
		value = value * roundingFactor;
		value = Math.round(value);
		return value / roundingFactor;
	}

	
	@Override public void paintComponent(Graphics g) {
        super.paintComponent(g);    // paints background
       
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        					RenderingHints.VALUE_ANTIALIAS_ON);
        
        int boxX = 10;
        g2.setPaint(EDGE_COLOR_LMT_HOLE);
        g2.fillRect(boxX, 5, 10, 10);
        
        g2.setPaint(EDGE_COLOR_IN);
        g2.fillRect(boxX, 20, 10, 10);
        
        g2.setPaint(EDGE_COLOR_CONVEX_HULL);
        g2.fillRect(boxX, 35, 10, 10);
        
        g2.setPaint(Color.black);
        g2.drawString("LMT-Hole", boxX + 20, 15);
        g2.drawString("LMT-Skeleton", boxX + 20, 30);
        g2.drawString("Convex Hull", boxX + 20, 45);
                
        if (triangulator != null) {
        	            
        	if (triangulator instanceof FastLMTTriangulator) {
        		
        		Font font = new Font("Dialog", Font.PLAIN, 10);
        		g2.setFont(font);
        		
        		g2.setPaint(Color.gray);
        		
        		int textX = boxX + 200;
        		g2.drawLine(textX, 5, textX, 50);
        		
        		FastLMTTriangulator ft = (FastLMTTriangulator)triangulator;
        		
        		int textY = 17;
        		g2.setPaint(Color.gray);
        		long edges = 0l;
        		int edgesWithoutMinimum = 0;
        		int nonIntersectingEdges = 0;
        		double totalTime = 0;
        		double timeGenerateEdges = 0;
        		double timeLMT = 0;
        		FastLMTSkeletonCreator creator = ft.getSkeletonCreator();
        		if (creator != null) {
        			Logger logger = creator.getLogger();
            		edges = logger.edgesCheckedForIntersection;
            		edgesWithoutMinimum = logger.edgesWithoutLocalMinimum;
            		nonIntersectingEdges = logger.nonIntersectingEdges;
            		totalTime = logger.time;
            		timeGenerateEdges = logger.timeGenerateEdges;
            		timeLMT = logger.timePartA + logger.timePartB;
				}
        		g2.drawString("Edges checked for intersection: " + edges, textX + 10, textY);
        		g2.drawString("Edges without local minimum: " + edgesWithoutMinimum, textX + 10, textY + 13);
        		g2.drawString("Non-Intersecting edges: " + nonIntersectingEdges, textX + 10, textY + 13 + 13);
        		
        		// Second line
        		int textX2 = textX + 230;
        		totalTime = round(totalTime);
        		g2.drawString("Total running time: " + totalTime + "s", textX2 + 10, textY);
        		timeGenerateEdges = round(timeGenerateEdges);
        		g2.drawString("Time to generate edges: " + timeGenerateEdges + "s", textX2 + 10, textY + 13);
        		timeLMT = round(timeLMT);
        		g2.drawString("Time to calculate LMT skeleton: " + timeLMT + "s", textX2 + 10, textY + 13 + 13);
        		
        	}
            if (progress != 0 && progress != 100) {
        		g2.setPaint(Color.red);
        		g2.drawString(progressText + progress, 130, 45);                 	
        	} 	
        }
   }
	
	public void setActiveTriangulator(EdgeGenerator triangulator) {
		this.triangulator = triangulator;
	}
	
	public void setTriangleDisplay(TriangleDisplay t) {
		triangleDisplay = t;
	}
	
	public void updateProgress(String text, int percent) {
		progressText = text;
		progress = percent;
		repaint();
	}
	
	@Override
	public void receiveNotification(Notification notification) {
		
		if (notification.name == Notification.willStartProcessing) {
			updateProgress("Processing ", 1);
		}
		
		if (notification.name == Notification.didProcessXPercent) {
			if ( ! (notification.sender instanceof Integer)) {
				return;
			}
			updateProgress("Processing ", (Integer)notification.sender);
		}
	}
}
